// dotnet $DOTNET_CSC_DLL -nologo -t:library -r:"../../The Scroll of Taiwu_Data/Managed/netstandard.dll" -r:"../../The Scroll of Taiwu_Data/Managed/0Harmony.dll" -r:"../../The Scroll of Taiwu_Data/Managed/mscorlib.dll" -r:"../../The Scroll of Taiwu_Data/Managed/Assembly-CSharp.dll" -r:"../../The Scroll of Taiwu_Data/Managed/TaiwuModdingLib.dll" -optimize -deterministic -debug NeutronLoader.cs *.CS -out:NeutronLoader.dll
// -r:"../../The Scroll of Taiwu_Data/Managed/Mono.Cecil.dll" -r:"../../The Scroll of Taiwu_Data/Managed/System.Core.dll"   -r:"../../The Scroll of Taiwu_Data/Managed/System.Composition.AttributedModel.dll"
/**
 *  Neutron's Taiwu Collections
 *  Copyright (C) 2022 Neutron3529
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#define FRONTEND

using System;
using System.Reflection;
using System.Collections.Generic;

using static Utils.Logger;
[assembly: AssemblyVersion("0.0.0.3529")]
namespace NeutronLoader;

public class Plugin {
    public static System.Type GetEntrypointType(System.Reflection.Assembly assembly)
    {
        System.Type typeFromHandle = typeof(TaiwuModdingLib.Core.Plugin.TaiwuRemakeHarmonyPlugin);
        System.Type typeFromHandle2 = typeof(TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin);
        System.Type[] exportedTypes = assembly.GetExportedTypes();
        System.Type[] array = exportedTypes;
        foreach (System.Type type in array)
        {
            logger(type.ToString());
            if (type.BaseType == typeFromHandle2 || type.BaseType == typeFromHandle)
            {
                return type;
            }
        }
        return null;
    }
    // GameData.Domains.Mod.ModId mod_id;
    GameData.Domains.Mod.ModInfo mod_info; // frontend only?
    AppDomain ad;
    TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin plugin=null;
    public Plugin(string modidstr){
        this.mod_info=ModManager.GetModInfo(modidstr);
        if(this.mod_info!=null){
            this.ad = AppDomain.CreateDomain("Neutron Handled "+modidstr, null, AppDomain.CurrentDomain.SetupInformation);
        }
    }
    public void Unload(){
        AppDomain.Unload(this.ad);
    }
    public System.Reflection.Assembly LoadAssembly(string dll){
        var pdb = System.IO.Path.ChangeExtension(dll, "pdb");
        return this.ad.Load(System.IO.File.ReadAllBytes(dll), System.IO.File.Exists(pdb)?System.IO.File.ReadAllBytes(pdb):null);
    }
    public void LoadPlugin(string file_name="Fine.dll"){
        try {
            var dll = System.IO.Path.Combine(mod_info.DirectoryName, file_name);
            logger("neutron loader loads "+dll);
            var assembly = this.LoadAssembly(dll);
            var referencedAssemblies = assembly.GetReferencedAssemblies();

            foreach (System.Reflection.AssemblyName assemblyName in referencedAssemblies) {
                dll = System.IO.Path.Combine(mod_info.DirectoryName, assemblyName.Name + ".dll");
                if (System.IO.File.Exists(dll)) {
                    AppDomain.CurrentDomain.Load(dll);
                }
            }
            System.Type entrypointType = GetEntrypointType(assembly);
            TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin taiwuRemakePlugin = (TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin)System.Activator.CreateInstance(entrypointType);
            if (taiwuRemakePlugin == null) {
                throw new System.Exception($"找不到{dll}里面的TaiwuRemakePlugin类，请联系此Mod的作者解决问题。");
            }
            typeof(TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin).GetField("ModIdStr").SetValue(taiwuRemakePlugin, new object[]{this.mod_info.ModId.ToString()});
            taiwuRemakePlugin.Initialize();
            this.plugin=taiwuRemakePlugin;
        } catch (System.Reflection.ReflectionTypeLoadException ex) {
            System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
            System.Exception[] loaderExceptions = ex.LoaderExceptions;
            foreach (System.Exception ex2 in loaderExceptions) {
                stringBuilder.AppendLine(ex2.Message);
            }
            throw new System.Exception(stringBuilder.ToString(), ex);
        }
    }
}

[TaiwuModdingLib.Core.Plugin.PluginConfig("NeutronLoader","Neutron3529","0.5.0")]
public class NeutronLoader : TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin {
    static Dictionary<string, Plugin> PluginDict= new Dictionary<string, Plugin>();
    public override void Initialize(){
        if(PluginDict.TryGetValue(ModIdStr, out var plugin)){
            logwarn($"PluginDict中残留有{ModIdStr}的AppDomain，卸载之。");
            plugin.Unload();
            PluginDict.Remove(ModIdStr);
        } else {
            logger($"正常加载：PluginDict中{ModIdStr}项");
        }
        try{
            plugin = new Plugin(ModIdStr);
            plugin.LoadPlugin("Fine.dll");
        } catch(Exception ex){
            logex(ex);
            plugin=null;
        }
        if(plugin!=null){
            PluginDict[ModIdStr]=plugin;
        }
    }
    public override void Dispose(){
        if(PluginDict.TryGetValue(ModIdStr, out var plugin)){
            logger($"正常卸载：PluginDict中{ModIdStr}项");
            plugin.Unload();
            PluginDict.Remove(ModIdStr);
        } else {
            logwarn($"PluginDict中{ModIdStr}项已被卸载，请通知中子检查螺舟执行逻辑！");
        }
    }
}
